﻿using System;
using System.Windows.Controls;
using System.Windows;
using System.Windows.Media;
using System.ComponentModel;
using System.Windows.Controls.Primitives;
using System.Windows.Media.Animation;
using System.Windows.Input;
using System.Diagnostics;
using UBCon.Ribbon.Interfaces;



namespace UBCon.Ribbon
{
    [TemplatePart(Name=PopupName, Type=typeof(Popup))]
    [TemplatePart(Name = PART_DropDownMenuItemsHost, Type=typeof(Panel))]
    public class DropDownMenuItem : MenuItem, IRibbonControl
    {
        #region Constructors

        static DropDownMenuItem() 
        {
            Type ownerType=typeof(DropDownMenuItem);
            DropDownMenuItem.DefaultStyleKeyProperty.OverrideMetadata(ownerType,
                new FrameworkPropertyMetadata(ownerType));

            DropDownMenuItem.IsSubmenuOpenProperty.OverrideMetadata(ownerType,
                new FrameworkPropertyMetadata(false, new PropertyChangedCallback(DropDownMenuItem.OnIsSubmenuOpenPropertyChanged)));
        }

        public DropDownMenuItem() : base() 
        {
        }

        #endregion

        #region Properties

        [Bindable(true), 
        ReadOnly(false), 
        Browsable(true), 
        Category("Appearance")]
        public ImageSource Image
        {
            get { return (ImageSource)GetValue(ImageProperty); }
            set { SetValue(ImageProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Image.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty ImageProperty = RibbonButton.ImageProperty.AddOwner(typeof(DropDownMenuItem));
        
        [Bindable(true),
        ReadOnly(false),
        Browsable(false)]
        public double MaxDropDownWidth
        {
            get { return (double)GetValue(MaxDropDownWidthProperty); }
            set { SetValue(MaxDropDownWidthProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MaxDropDownWidth.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MaxDropDownWidthProperty =
            DependencyProperty.Register("MaxDropDownWidth", typeof(double), 
            typeof(DropDownMenuItem), 
            new PropertyMetadata(250.0D));

        #endregion

        #region Depenency Property Changed Callbacks

        private static void OnIsSubmenuOpenPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            DropDownMenuItem menuItem = (DropDownMenuItem)sender;
            bool newValue = (bool)e.NewValue;
            bool oldValue = !newValue;
            if (menuItem.ContentCanBeAnimated)
            {
                if (menuItem.Role == MenuItemRole.SubmenuHeader || menuItem.Role == MenuItemRole.TopLevelHeader)
                {
                    if (newValue)
                    {
                        menuItem.TryAnimateDropDownContent();   
                    }
                   
                }
            }
        }
      
        #endregion

        #region Overrides

        /// <summary>
        /// Invoked when UBCom.Ribbon.DropDownMenuItem is pressed.
        /// </summary>
        protected override void OnClick()
        {
            CloseParentsPopup();

            base.OnClick();
        }

        /// <summary>
        /// Invoked whenever application code or internal processes (such as a rebuilding layout pass) call ApplyTemplate. 
        /// In simplest terms, this means the method is called just before a UI element displays in  app.  
        /// </summary>
        public override void OnApplyTemplate()
        {
            _dropDownPopup = GetTemplateChild(PopupName) as Popup;

            if (ContentCanBeAnimated)
            {
                RestoreContent();
            }

            base.OnApplyTemplate();
        }

        /// <summary>
        ///Creates or identifies the element that is used to display the given item.
        /// </summary>
        /// <returns>Type: System.Windows.DependencyObject. The element that is used to display the given item.</returns>
        protected override DependencyObject GetContainerForItemOverride()
        {
            DropDownMenuItem menuItem = new DropDownMenuItem();
            if (ParentMenu != null) 
            {
                menuItem.ParentMenu = ParentMenu;
            }
            return menuItem;
        }

        /// <summary>
        /// Determines if the specified item is (or is eligible to be) its own ItemContainer. 
        /// (Overrides ItemsControl.IsItemItsOwnContainerOverride(Object).)
        /// </summary>
        /// <param name="item">Specified item.</param>
        /// <returns>true if the item is its own ItemContainer; otherwise, false.</returns>
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            bool _isValidItem = item is DropDownMenuItem;
            if (_isValidItem&&ParentMenu!=null) 
            {
                DropDownMenuItem menuItem = item as DropDownMenuItem;
                if (menuItem.ParentMenu == null) 
                {
                    menuItem.ParentMenu = ParentMenu;
                }
            }
            return _isValidItem || item is RibbonSeparator || item is RibbonGallerySet;;
        }
        #endregion

        #region Private Utilities

        private void CloseParentsPopup() 
        {
            if (ParentMenu != null && !StaysOpenOnClick && ParentMenu.IsDropDownOpen)
            {
                ParentMenu.CloseDropDown();
            }
        }

        private void BuildShowContentAnimation()
        {
            //System.Windows.Media.Animation.

            DoubleAnimation da = new DoubleAnimation() { EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseOut, Exponent = 5 } };
            TranslateTransform transform = this._dropDownPopup.Child.RenderTransform as TranslateTransform;
            Storyboard.SetTargetProperty(da, new PropertyPath(propertyPath));
            Storyboard.SetTarget(da, this.DropDownContent);
            this.ShowContentStoryboard = new Storyboard();
            da.From = -5D;
            da.To = 0.0D;
            da.Duration = new Duration(TimeSpan.FromSeconds(0.09));
            this.ShowContentStoryboard.Children.Add(da);
        }

        private void BuildHideContentStoryboard()
        {
            this.HideContentStoryboard = new Storyboard();
            DoubleAnimation da = new DoubleAnimation();
            Storyboard.SetTargetProperty(da, new PropertyPath(propertyPath));
            Storyboard.SetTarget(da, this.DropDownContent);
            da.From = 0.0D;
            da.To = -5;
            da.Duration = new Duration(TimeSpan.FromSeconds(0.02));
            this.HideContentStoryboard.Children.Add(da);
        }
        #endregion

        #region Event Handlers
        #endregion

        #region Fields

        private const string PopupName = "Popup";

        //property path to animate
        private const string propertyPath = "(UIElement.RenderTransform).(TranslateTransform.X)";

        //Template part names
        private const string PART_DropDownMenuItemsHost = "PART_DropDownMenuItemsHost";

        protected Popup _dropDownPopup;

        //content animation
        private Storyboard ShowContentStoryboard, HideContentStoryboard;

        internal DropDownButtonBase ParentMenu { get; set; }

        #endregion

        #region Events
        #endregion

        #region Protected methods and properties

        /// <summary>
        /// 
        /// </summary>
        protected void TryAnimateDropDownContent()
        {
            if (ContentCanBeAnimated)
            {
                if (ShowContentStoryboard == null)
                {
                    BuildShowContentAnimation();
                }
                ShowContentStoryboard.Begin();
            }
        }

        /// <summary>
        /// Gets drop down's content
        /// </summary>
        protected FrameworkElement DropDownContent
        {
            get { return _dropDownPopup.Child as FrameworkElement; }
        }

        /// <summary>
        /// Indicates whether drop down content can be animated or not
        /// </summary>
        protected bool ContentCanBeAnimated
        {
            get
            {
                return _dropDownPopup != null
                        && _dropDownPopup.Child != null
                            && _dropDownPopup.Child is FrameworkElement
                            && _dropDownPopup.Child.RenderTransform is TranslateTransform;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        protected void RestoreContent()
        {
            if (ContentCanBeAnimated)
            {
                if (HideContentStoryboard == null)
                {
                    BuildHideContentStoryboard();
                }
                HideContentStoryboard.Begin();
            }
        }
        
        #endregion

        #region IRibbonControl Implementation

        /// <summary>
        /// Gets a boolean value indicating whether the contol's size is large
        /// </summary>
        public bool IsLarge
        {
            get { return true; }
        }

        #endregion
    }
}
